#!/usr/bin/env python
#=======================================================================
#
#          FILE: objdump_parser.py
#         USAGE: ./objdump_parser.py objdump_parser.py <func+off> <mod>
#   DESCRIPTION: Parse Linux kernel oops using objdump
#  REQUIREMENTS: objdump
#          BUGS: N/A
#         NOTES: N/A
#        AUTHOR: Ali Ayoub
#         EMAIL: ali@mellanox.com
#       COMPANY: N/A
#       CREATED: 09.17.2010-15:29:28
#      REVISION: 1.0
#=======================================================================

import os
import sys
import time

SNAME = os.path.basename(sys.argv[0])
USAGE = "%s <func+off> <mod>" % (SNAME)
EXAMPLE = "%s %s %s" % (SNAME, "fip_vnic_login_create_1+0x4a", "mlx4_vnic.o")

# print functions
debug = "--debug" in sys.argv
if debug:
	sys.argv.remove("--debug")

def vprint(msg):
	if debug:
		print "-V- %s" % msg

def eprint(msg):
	print "-E- %s" % msg

def iprint(msg):
        print "-I- %s" % msg

def main():
	if len(sys.argv[1:]) != 2:
		eprint("Bad Args")
		iprint("USAGE: %s" % USAGE)
		iprint("EXAMPLE: %s" % EXAMPLE)
		return 1

	trace = sys.argv[1]
	trace_func = trace.split('+')[0]
	trace_off = trace.split('+')[1]
	mod = sys.argv[2]
	objdump_f = "/tmp/%s.%s" % (os.path.basename(mod), time.time())
	print objdump_f
	if (os.system("objdump -Sld %s > %s" % (mod, objdump_f))):
		eprint("objdump failed")
		return 1
	vprint("objdump output %s" % objdump_f)
	objdump_fd = open(objdump_f)
	objdump_lines = objdump_fd.readlines()
	objdump_fd.seek(0)
	objdump_out = objdump_fd.read()

	addr = 0
	index = 0
	addr_index = 0
	token = "<%s>:" % trace_func
	vprint("looking for %s in %s" % (token, objdump_f))

	for line in objdump_lines:
		index = index + 1
		if not line.count(token):
			continue
		addr_index = index
		vprint("found func %s at line %s (%s+%s)" % (trace_func, line.strip(), objdump_f, addr_index))
		_addr = line.split()[0]
		addr = hex(int(_addr, 16) + int(trace_off, 16))
		break

	if addr == 0:
		eprint("couldn't find func %s" % trace_func)
		return 1

	vprint("%s -> %s" % (trace, addr))

	# look for assembly line
	found_line_index = 0
	for i in range(int(addr, 16) + 4, int(addr, 16) - 16, -1):
		token = "%s:" % hex(i)
		token = token.replace("0x", '')
		vprint("looking for hex add %s" % token)
		index = 0
		for line in objdump_lines:
			index = index + 1
			if line.strip().startswith(token):
				found_line_index = index
				break
		if found_line_index:
			break

	if not found_line_index:
                eprint("couldn't find found_line_index: %s" % found_line_index)
                return 2

	vprint("found_line_index: %s" % str(found_line_index))

	# print result
	found_start_index = addr_index - 1
	code_line=0
	for i in range(found_start_index, found_line_index):
		#print objdump_lines[i].strip()
		if objdump_lines[i].strip().count(".c:") or objdump_lines[i].strip().count(".h:"):
			code_line = i
	if code_line:
		print ("%s = %s => %s" % (trace, addr, objdump_lines[code_line].strip()))
	# cleanup
	objdump_fd.close()
	#os.remove(objdump_f)

	return 0

if __name__ == '__main__':
	try:
		rc = main()
	except Exception, e:
		rc = 1
		print "-E- Exception %s" % str(e)
		print "-E- Abort."
	sys.exit(rc)

